home *** CD-ROM | disk | FTP | other *** search
- PROGRAM Texture1;
- {
- Real Texture Mapping
- - by Bjarke Viksφe
- aug 1994
-
- Texture mapping done on a tweaked screen 320x200x256 !
- Texture is 128x128 in 256 colours. File is 'marble.lbm'.
- However, the texturebuffer is 256x256 for fast access!
-
- If it jerks on your (slower) computer try setting the BOX constant a
- bit lower.
-
- The texture inner loop looks like this:
- ╔═════════════╦═══════════════════════════╗
- ║ UPPER 16BIT ║ LOWER 16BIT ║
- ╔═══════╬═════════════╬═════════════╦═════════════╣ Inner: add ecx,eax
- ║ REG ║ HI WORD ║ HI BYTE ║ LO BYTE ║ adc ebx,ebp
- ╠═══════╬═════════════╬═════════════╬═════════════╣ adc bh,dl
- ║ EAX ║ X-INC LSW ║ --- ║ --- ║ mov dh,[ds:bx]
- ╠═══════╬═════════════╬═════════════╬═════════════╣ mov [es:di],dh
- ║ ECX ║ TXT-X LSW ║ --- ║ LOOPCOUNT ║ add di,80
- ╠═══════╬═════════════╬═════════════╬═════════════╣ loop Inner
- ║ EDX ║ --- ║ TEXTUREDATA ║ Y-INC ║
- ╠═══════╬═════════════╬═════════════╬═════════════╣
- ║ EBP ║ Y-INC LSW ║ X-INC SIGN ║ X-INC ║
- ╠═══════╬═════════════╬═════════════╬═════════════╣
- ║ EBX ║ TXT-Y LSW ║ TEXTURE Y ║ TEXTURE X ║
- ╚═══════╩═════════════╩═════════════╩═════════════╝
- (Rest easy, this is not something I just figured out. I peeked at some
- code from a dude called Fantom/UBP. Also read the PCGPE. It has great
- articles about texture mapping!)
- }
-
- {$A+,B-,G+,E+,I+,N-,X+}
- {$C FIXED PRELOAD PERMANENT}
-
- {$DEFINE DEBUG}
-
- USES
- DEMOINIT,ILBM256,PICTURE;
-
- CONST
- NUMBER_FACES = 6;
- NUMBER_COORDS = 8;
- BOX = 110; {size of box}
-
- TYPE
- SlopeType = array[0..319*2] of integer;
-
- FaceType = RECORD
- l1,l2,l3,l4 : byte;
- end;
-
-
- VAR
- slope,textureslope : SlopeType;
- face : array[1..NUMBER_FACES] of FaceType;
- cbuffer : array[0..NUMBER_COORDS*2-1] of integer;
-
- minx,maxx : integer;
-
- sinustabel : array[0..639] of integer;
- v1,v2,v3 : word; {rotation angle}
- cos1,sin1,cos2,sin2,cos3,sin3 : integer;
-
- texture : pScreen;
-
-
- CONST
- display1 : word = $0000;
- display2 : word = $4000;
- {setup coords for a box}
- coords : array[0..NUMBER_COORDS*3-1] of integer =
- (box,box,-box, -box,box,-box, -box,-box,-box, box,-box,-box,
- box,box,box, -box,box,box, -box,-box,box, box,-box,box);
-
-
- (*------------------------------------------------*)
-
- procedure SetupSinus;
- var
- i : integer;
- v, vadd : real;
- begin
- v:=0.0;
- vadd:=(2.0*pi/512.0);
- for i:=0 to 639 do begin
- sinustabel[i]:=round(sin(v)*32767);
- v:=v+vadd;
- end;
- end;
-
- procedure SetupFaces;
- {setup faces. Make sure face keeps track of which coordinates it uses!}
- begin
- with face[1] do begin l1:=3; l2:=2; l3:=1; l4:=0; end;
- with face[2] do begin l1:=4; l2:=5; l3:=6; l4:=7; end;
- with face[3] do begin l1:=0; l2:=1; l3:=5; l4:=4; end;
- with face[4] do begin l1:=1; l2:=2; l3:=6; l4:=5; end;
- with face[5] do begin l1:=2; l2:=3; l3:=7; l4:=6; end;
- with face[6] do begin l1:=3; l2:=0; l3:=4; l4:=7; end;
- end;
-
- procedure InitDemo;
- var
- i,j,k : word;
- begin
- Screen_Off;
- ClearWholeScreen;
- SetupSinus;
- SetupFaces;
-
- New(texture); {load picture}
- LoadPix(texture,'marble.lbm');
- j:=0; k:=0;
- {picture is 320x200. Need to convert it to 256x128}
- for i:=1 to 128 do begin
- Move(texture^[j],texture^[k],128);
- inc(j,320);
- inc(k,256);
- end;
- SetCMAP;
-
- v1:=0; v2:=0; v3:=0;
-
- Screen_On;
- end;
-
- procedure UninitDemo;
- begin
- Dispose(texture);
- end;
-
-
- (*------------------------------------------------*)
-
- procedure SwapDisplay;
- var
- temp : word;
- begin
- temp:=display2;
- display2:=display1;
- display1:=temp;
- SetAddress(Ptr(SEGA000,display2));
- end;
-
- procedure ClearScreen; assembler;
- asm
- mov dx,$3C4
- mov ax,$0F02
- out dx,ax
-
- mov es,SEGA000
- mov di,display1
- add di,(30*WIDTH)+16
- mov dx,140
- xor ax,ax
- mov bx,48/2
- @loop:
- mov cx,bx
- rep stosw
- add di,WIDTH-48
- dec dl
- jnz @loop
- end;
-
-
- (*------------------------------------------------*)
-
- procedure ClearSlope; assembler;
- asm
- mov ax,ds
- mov es,ax
- lea di,slope
- DB LONG; mov ax,$8000; DW $8000;
- cld
- mov cx,TYPE(slopetype)/4
- rep; DB LONG; stosw
- end;
-
- procedure CalcSlope(l1,l2 : integer; tex1a,tex1b,tex2a,tex2b : word); assembler;
- var
- tex1add,tex2add : word;
- xlowadd,xhighadd : word;
- ysize : integer;
- asm
- lea si,cbuffer
- DB LONG; xor cx,cx
- mov bx,l1 {get first coords}
- shl bx,2
- mov dx,[si+bx] {get x/y coords}
- mov cx,[si+bx+2]
-
- mov ax,l2 {get second coords}
- shl ax,2
- add si,ax
- mov ax,[si] {get x/y coords}
- mov bx,[si+2]
-
- cmp bx,cx {make sure we go downwards...}
- jle @noswap
- mov si,tex1a {swap texture x}
- xchg tex1b,si
- mov tex1a,si
- mov si,tex2a {swap texture y}
- xchg tex2b,si
- mov tex2a,si
- xchg ax,dx {swap x}
- xchg bx,cx {sway y}
- @noswap:
-
- cmp bx,minx {record miny and maxy}
- jge @minx
- mov minx,bx
- @minx:
- cmp cx,maxx
- jle @maxx
- mov maxx,cx
- @maxx:
-
- sub cx,bx
- and cx,cx
- jnz @notzero
- jmp @zero
- @notzero:
- mov ysize,cx
- add bx,bx
- add bx,bx
- lea si,slope
- add si,bx
-
- push ax
- sub dx,ax
- inc dx
-
- mov ax,dx
- DB LONG; shl ax,16
- {cdq} DB $66,$99
- DB LONG; idiv cx
- DB LONG; mov dx,ax
- DB LONG; shr dx,16
- mov xlowadd,ax
- mov xhighadd,dx
-
- mov al,BYTE PTR tex1a
- mov ah,BYTE PTR tex1b
- sub ah,al
- xor al,al
- cwd
- idiv cx
- mov tex1add,ax
-
- mov al,BYTE PTR tex2a
- mov ah,BYTE PTR tex2b
- sub ah,al
- xor al,al
- cwd
- idiv cx
- mov tex2add,ax
- @one:
- pop cx
-
- xor bx,bx
- mov ah,BYTE PTR tex1a
- xor al,al
- mov dh,BYTE PTR tex2a
- xor dl,dl
- mov di,$8000
- @loop:
- cmp [si],di
- jne @other
- mov [si],cx
- mov [si+TYPE(SlopeType)],ah
- mov [si+TYPE(SlopeType)+1],dh
- add si,4
- add bx,xlowadd
- adc cx,xhighadd
- add ax,tex1add
- add dx,tex2add
- dec ysize
- jnz @loop
- jmp NEAR PTR @zero
- @other:
- mov [si+2],cx
- mov [si+TYPE(SlopeType)+2],ah
- mov [si+TYPE(SlopeType)+3],dh
- add si,4
- add bx,xlowadd
- adc cx,xhighadd
- add ax,tex1add
- add dx,tex2add
- dec ysize
- jnz @loop
- @zero:
- end;
-
-
- (*------------------------------------------------*)
-
- procedure CalcAngle;
- begin
- sin1:=sinustabel[v1]; cos1:=sinustabel[v1+128];
- sin2:=sinustabel[v2]; cos2:=sinustabel[v2+128];
- sin3:=sinustabel[v3]; cos3:=sinustabel[v3+128];
- v1:=(v1+2) AND 511;
- v2:=(v2-1) AND 511;
- v3:=(v3+1) AND 511;
- end;
-
- procedure RotateAllCoords; assembler;
- {Rotate all coords in "coords" around all 3 axis and make
- perspective calcualtion. Store x,y,z results in "cbuffer"}
- var
- xkoord,ykoord,zkoord, n : integer;
- asm
- mov ax,ds
- mov es,ax
- lea si,coords
- lea di,cbuffer
- mov n,NUMBER_COORDS
- cld
- @loop:
- lodsw
- mov xkoord,ax
- lodsw
- mov ykoord,ax
- lodsw
- mov zkoord,ax
-
- mov ax,xkoord {rotate around Z-axis}
- push ax
- imul Cos1
- add ax,ax
- adc dx,dx
- mov bx,dx
- mov ax,ykoord
- imul Sin1
- add ax,ax
- adc dx,dx
- sub bx,dx
- mov xkoord,bx
- pop ax
- imul Sin1
- add ax,ax
- adc dx,dx
- mov bx,dx
- mov ax,ykoord
- imul Cos1
- add ax,ax
- adc dx,dx
- add bx,dx
- mov ykoord,bx
-
- mov ax,ykoord {rotate around Y-axis}
- push ax
- imul Cos2
- add ax,ax
- adc dx,dx
- mov bx,dx
- mov ax,zkoord
- imul Sin2
- add ax,ax
- adc dx,dx
- sub bx,dx
- mov ykoord,bx
- pop ax
- imul Sin2
- add ax,ax
- adc dx,dx
- mov bx,dx
- mov ax,zkoord
- imul Cos2
- add ax,ax
- adc dx,dx
- add bx,dx
- mov zkoord,bx
-
- mov ax,xkoord {rotate around X-axis}
- push ax
- imul Cos3
- add ax,ax
- adc dx,dx
- mov bx,dx
- mov ax,zkoord
- imul Sin3
- add ax,ax
- adc dx,dx
- sub bx,dx
- mov xkoord,bx
- pop ax
- imul Sin3
- add ax,ax
- adc dx,dx
- mov bx,dx
- mov ax,zkoord
- imul Cos3
- add ax,ax
- adc dx,dx
- add bx,dx
- mov zkoord,bx
-
- add bx,800
- and bx,bx
- jnz @zero
- mov bl,1
- @zero:
-
- mov ax,xkoord
- cwd
- mov dl,ah
- mov ah,al
- xor al,al
- idiv bx
- add ax,100
- stosw
-
- mov ax,ykoord
- cwd
- mov dl,ah
- mov ah,al
- xor al,al
- idiv bx
- add ax,160
- stosw
-
- dec n
- jnz @loop
- end;
-
-
-
- function FaceShown(l1,l2,l3 : word) : boolean;
- var
- a,b : longint;
- begin
- a := longmul(cbuffer[l1]-cbuffer[l2],cbuffer[l3+1]-cbuffer[l2+1]);
- b := longmul(cbuffer[l1+1]-cbuffer[l2+1],cbuffer[l3]-cbuffer[l2]);
- FaceShown := (a-b) > 0;
- end;
-
-
- procedure FillShape(x,xsize : integer); assembler;
- var
- tex1,tex2 : word;
- xlowadd,xhighadd,ylowadd,yhighadd : word;
- loops : word;
- asm
- cmp xsize,320
- jb @drawit
- jmp @done
- @drawit:
- mov di,display1
- mov ax,x
- shr ax,2
- add di,ax
-
- lea si,slope
- mov ax,x
- shl ax,2
- add si,ax
-
- mov es,SEGA000
- cld
- @xloop:
- mov cx,x
- and cl,3
- mov al,1
- shl al,cl
- mov ah,al
- mov dx,$3C4
- mov al,$02
- out dx,ax
-
- mov cx,[si+TYPE(slopetype)] {fetch texture x,y values}
- lodsw {fetch first xpos}
- mov dx,ax
- mov bx,[si+TYPE(slopetype)] {fetch second texture values}
- lodsw {fetch second xpos}
- cmp ax,dx {need to go from left to right..}
- jle @exchange
- xchg ax,dx
- xchg cx,bx
- @exchange:
- mov tex1,cx
- mov tex2,bx
-
- push si
- push di
-
- DB LONG; xor cx,cx
- mov cx,dx
- sub cx,ax
- or cx,cx
- jnz @y_is_great
- jmp @filledout
- @y_is_great:
- add ax,ax
- mov bx,ax
- add di,[OFFSET ytabel+bx]
- mov loops,cx
-
- push ds
-
- mov al,BYTE PTR tex1
- sub al,BYTE PTR tex2
- cbw
- DB LONG; shl ax,16
- {cdq} DB $66,$99
- DB LONG; idiv cx
- DB LONG; mov dx,ax
- DB LONG; shr dx,16
- mov xlowadd,ax
- mov xhighadd,dx
-
- mov al,BYTE PTR tex1+1
- sub al,BYTE PTR tex2+1
- cbw
- DB LONG; shl ax,16
- {cdq} DB $66,$99
- DB LONG; idiv cx
- DB LONG; mov dx,ax
- DB LONG; shr dx,16
- mov ylowadd,ax
- mov yhighadd,dx
-
- DB LONG; xor dx,dx
- mov dx,yhighadd
-
- mov ax,xlowadd
- DB LONG; shl ax,16
-
- mov bx,ylowadd
- DB LONG; shl bx,16
- mov bx,xhighadd
- DB LONG; mov si,bx
-
- DB LONG; xor bx,bx
- mov bl,BYTE PTR tex2
- mov bh,BYTE PTR tex2+1
- DB LONG; xor cx,cx
- mov cx,loops
- mov ds,WORD PTR texture+2
- @loop:
- DB LONG; add cx,ax
- DB LONG; adc bx,si
- adc bh,dl
- mov dh,[bx]
- mov [es:di],dh
- add di,80
- dec cx
- jnz @loop
-
- pop ds
-
- @filledout:
- pop di
- pop si
- @filledout_fast:
- inc x
- test x,3
- jnz @no_address_add
- inc di
- @no_address_add:
- dec xsize
- jnz @xloop
- @done:
- end;
-
-
- procedure RunOnce;
- var
- i : integer;
- begin
- SwapDisplay;
- VBLANK;
- {$IFDEF DEBUG}
- SetRGB(0,16,0,0);
- {$ENDIF}
-
- ClearScreen;
-
- CalcAngle;
- RotateAllCoords;
-
- for i:=1 to NUMBER_FACES do begin
- with face[i] do if FaceShown(l1 SHL 1,l2 SHL 1,l3 SHL 1) then begin
- ClearSlope;
- minx := 320; maxx := 0;
- CalcSlope(l1,l2, 0,0,127,0);
- CalcSlope(l2,l3, 127,0,127,127);
- CalcSlope(l3,l4, 127,127,0,127);
- CalcSlope(l4,l1, 0,127,0,0);
- FillShape(minx, maxx-minx);
- end;
- end;
-
- {$IFDEF DEBUG}
- SetRGB(0,0,0,0);
- while KeyHit[26] do ; {Hit 'P' to pause}
- {$ENDIF}
- end;
-
-
- begin
- OpenScreen;
- InitDemo;
- SetAllInterrupts;
- repeat RunOnce until Key='e';
- RestoreAllInterrupts;
- UninitDemo;
- CloseScreen;
- end.
-